package geom

import "math"

type Vec2 struct {
	X, Y float64
}

type Vec2F32 struct {
	X, Y float32
}

func (f Vec2F32) ToVec2() Vec2 {
	return NewVec2(float64(f.X), float64(f.Y))
}

type VecUV struct {
	U, V float64
}

func (u VecUV) ToVec2(s Size) Vec2 {
	return Vec2{u.U * s.Width, u.V * s.Height}
}

func NewVec2(x, y float64) Vec2 {
	return Vec2{X: x, Y: y}
}

func NewVec2FromF32(x, y float32) Vec2 {
	return Vec2{X: float64(x), Y: float64(y)}
}

func (v Vec2) Add(other Vec2) Vec2 {
	return Vec2{v.X + other.X, v.Y + other.Y}
}

func (v Vec2) Sub(other Vec2) Vec2 {
	return Vec2{v.X - other.X, v.Y - other.Y}
}

func (v Vec2) Mul(n float64) Vec2 {
	return Vec2{v.X * n, v.Y * n}
}

func (v Vec2) ScalarMul(v2 Vec2) float64 {
	return v.X*v2.X + v.Y*v2.Y
}

func (v Vec2) MulXY(x float64, y float64) Vec2 {
	return Vec2{v.X * x, v.Y * y}
}

func (v Vec2) Div(f float64) Vec2 {
	return Vec2{v.X / f, v.Y / f}
}

func (v Vec2) Length() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v Vec2) Normalize() Vec2 {
	if v.X == 0 && v.Y == 0 {
		return v
	}
	return v.Mul(1 / v.Length())
}

func (v Vec2) ToRadian() Radian {
	return Radian(math.Atan2(v.Y, v.X))
}

func (v Vec2) Rotate(angle Radian) Vec2 {
	l := v.Length()
	a := v.ToRadian() + angle
	return a.ToVec().Mul(l)
}

func (v Vec2) RotateAround(angle Radian, b Vec2) Vec2 {
	return v.Sub(b).Rotate(angle).Add(b)
}

func (v Vec2) InRectWithoutRotation(pos Vec2, size Size) bool {
	v = v.Sub(pos)
	return v.X >= 0 && v.X <= size.Width && v.Y >= 0 && v.Y <= size.Height
}

func (v Vec2) AsPoint() Point {
	return Point{X: v.X, Y: v.Y}
}

func (v Vec2) ToSize() Size {
	return Size{Width: v.X, Height: v.Y}
}

func (v Vec2) ToVec2F32() Vec2F32 {
	return Vec2F32{X: float32(v.X), Y: float32(v.Y)}
}

func CalcCenter(points []Vec2) *Vec2 {
	if len(points) == 0 {
		return nil
	}
	res := Vec2{0, 0}
	for _, v := range points {
		res = res.Add(v)
	}
	res = res.Div(float64(len(points)))
	return &res
}
